package nirvana.core.bean.aspect;


import cn.hutool.json.JSONUtil;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j2;
import nirvana.core.domains.ann.Operation;
import nirvana.core.context.WebContext;
import nirvana.core.domains.dto.OperationLogDto;
import nirvana.core.security.SecurityCredential;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * LogRecordAspect   记录请求日志
 *
 * @author linkanyway
 */
@Aspect
@Component
@Log4j2
public class LogRecordAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);

    private final StringRedisTemplate stringRedisTemplate;

    private final HttpServletRequest request;

    public LogRecordAspect(StringRedisTemplate stringRedisTemplate, HttpServletRequest request) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.request = request;
    }

    /**
     *
     */
    @Pointcut("execution(public nirvana..ApiResult com..controller..*(..))")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void beforeMethod(JoinPoint joinPoint) {
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = servletRequestAttributes.getRequest();

        String requestURI = request.getRequestURI();
        String method = request.getMethod();
        String remoteAddr = request.getRemoteAddr();
        Object[] args = joinPoint.getArgs();

        StringBuilder builder = new StringBuilder();
        Object[] wrapArgs = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse || args[i] instanceof MultipartFile) {
                continue;
            }
            wrapArgs[i] = args[i];
        }
        String parameters = "";
        if (wrapArgs != null) {
            try {
                parameters = JSONUtil.toJsonStr(wrapArgs);
            } catch (Exception e) {
                parameters = wrapArgs.toString();
            }

            Long requestId = WebContext.getRequestId();
            Long currentUserId = WebContext.getCurrentUserId();

            builder.append("--- request information --------")
                    .append("request time: ").append(new SimpleDateFormat("yyyy MM DD HH: mm: SS").format(new Date()))
                    .append("remoteAddress:").append(remoteAddr)
                    .append("requestURI ").append(requestURI)
                    .append("Controller : ").append(joinPoint.getTarget().getClass())
                    .append("method type:").append(method)
                    .append("req param: ").append(parameters)
                    .append("requestId: ").append(requestId)
                    .append("currentUserId: ").append(currentUserId)
                    .append("--- request information -------- ---");
            String jsonString = builder.toString();

            logger.info("--- request information --------");
            logger.info(jsonString);

            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method signatureMethod = signature.getMethod();
            Operation ann = signatureMethod.getAnnotation(Operation.class);
            if (ann != null) {
                //记录操作日志
                String event = ann.value();
                String type = ann.type();

                String ipAddress = getClientIp(request);

                OperationLogDto logDto = new OperationLogDto();
                logDto.setIpAddress(ipAddress);
                logDto.setUserId(currentUserId);
                logDto.setType(type);
                logDto.setOperationEvent(event);
                logDto.setOperationContent(parameters);
                logDto.setOperationTime(Timestamp.valueOf(LocalDateTime.now()));

                ListOperations<String, String> forList = stringRedisTemplate.opsForList();
                forList.leftPush("OPERATION_RBAC_LOG_LIST",JSONUtil.toJsonStr(logDto));

                return;
            }
        }

    }


    /**
     * 获取客户端ip
     * @param request
     * @return
     */
    public String getClientIp(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        return ipAddress;
    }

}